package server;

import db.Room;
import db.Token;
import db.User;
import mapper.RoomMapper;
import mapper.TokenMapper;
import mapper.UserMapper;
import result.CodeMsg;
import result.Result;

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.sql.ResultSet;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * @author 化尘成影
 * @Description 服务器启动类
 * @date 2022/6/9 19:48
 */
public class Server {
    private final int Port = 9918;
    private ServerSocket serverSocket;
    private static UserMapper userMapper = new UserMapper();
    private static TokenMapper tokenMapper = new TokenMapper();
    private static RoomMapper roomMapper = new RoomMapper();
    private static Set<String> userSet = new HashSet<>();
    private static Map<String, ObjectOutputStream> oosMap = new HashMap<>();
    private static Map<String, ObjectOutputStream> connectMap = new HashMap<>();
    private static Map<String, String> isOnline = new HashMap<>();


    public static void main(String[] args) {
        System.out.println("服务器启动");
        Server server = new Server();
        server.start();
    }

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    serverSocket = new ServerSocket(9919);
                    while (true) {
                        Socket accept = serverSocket.accept();
                        System.out.println("用户连接");
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                request(accept);
                            }
                        }).start();
                    }
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
        }).start();
    }

    public static void request(Socket socket) {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            while (true) {
                try {
                    String req = ois.readUTF();
                    //登录注册拦截器，防止同一ip设备重复登录或多窗口登录
//                    if (Objects.equals(req, "login") || Objects.equals(req, "register")) {
//                        Result result = new Result();
//                        if (isOnline.get(socket.getInetAddress().toString()) != null) {
//                            result.setCodeMsg(CodeMsg.IP_EXISTENT);
//                            oos.writeObject(result);
//                            continue;
//                        }
//                    }
                    switch (req) {
                        //登录
                        case "login" -> {
                            //组装返回类
                            Result result = new Result();
                            HashMap<String, String> map = new HashMap<>();

                            HashMap<String,String> requestMap = (HashMap<String,String>) ois.readObject();

                            User user = new User(requestMap.get("username"), requestMap.get("password"));
                            CodeMsg login = userMapper.login(user);

                            if (login.getCode() == 200) {
                                isOnline.put(socket.getInetAddress().toString(), user.getUsername());

                                if (userSet.add(user.getUsername())) {
                                    System.out.println(user.getUsername());
                                    oosMap.put(user.getUsername(), oos);
                                } else {
                                    result.setCodeMsg(CodeMsg.HAVE_LOGIN);
                                    oos.writeObject(result);
                                    return;
                                }
                                if(requestMap.get("token").equals("yes")){
                                    //保存token
                                    String token = UUID.randomUUID().toString();
                                    tokenMapper.insert(token, user.getUsername());
                                    map.put("token",token);
                                }

                                map.put("username", user.getUsername());
                                result.setCodeMsg(login);
                                result.setMap(map);
                                oos.writeObject(result);
                                oos.flush();
                            } else {
                                result.setCodeMsg(login);
                                oos.writeObject(result);
                                oos.flush();
                            }
                        }
                        case "loginByToken" -> {
                            //组装返回类
                            Result result = new Result();
                            HashMap<String, String> resultMap = new HashMap<>();
                            HashMap<String, String> requestMap = (HashMap<String, String>) ois.readObject();

                            Token token = tokenMapper.select(requestMap.get("token"));
                            if (!Objects.isNull(token)) {
                                String username = token.getUsername();
                                long createTime = token.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                                //时间间隔是否少于三天,否则返回token过期
                                if((new Date().getTime() - createTime) > 1000*60*60*24*3){
                                    tokenMapper.deleteByToken(requestMap.get("token"));
                                    result.setCodeMsg(CodeMsg.TOKEN_OUT_TIME);
                                    oos.writeObject(result);
                                    oos.flush();
                                    break ;
                                }
                                isOnline.put(socket.getInetAddress().toString(), username);
                                if (userSet.add(username)) {
                                    oosMap.put(username, oos);
                                } else {
                                    result.setCodeMsg(CodeMsg.HAVE_LOGIN);
                                    oos.writeObject(result);
                                    oos.flush();
                                    break ;
                                }
                                result.setCodeMsg(CodeMsg.SUCCESS);
                                resultMap.put("username", username);
                                result.setMap(resultMap);
                                oos.writeObject(result);
                                oos.flush();
                            } else {
                                //token无效
                                result.setCodeMsg(CodeMsg.TOKEN_INVALID);
                                oos.writeObject(result);
                                oos.flush();
                            }
                        }
                        //注册
                        case "register" -> {
                            HashMap<String,String> requestMap = (HashMap<String,String>) ois.readObject();
                            Result result = new Result();

                            User user = new User(requestMap.get("username"),requestMap.get("password"));
                            CodeMsg insert = userMapper.insert(user);
                            result.setCodeMsg(insert);
                            oos.writeObject(result);
                            oos.flush();
                        }
                        //创建房间
                        case "create" -> {
                            HashMap<String,String> requestMap = (HashMap<String,String>) ois.readObject();
                            Result result = new Result();
                            if (Objects.isNull(roomMapper.selectByRoomId(requestMap.get("createId")))) {
                                roomMapper.insert(requestMap.get("createId"), requestMap.get("fromUser"));
                                result.setCodeMsg(CodeMsg.SUCCESS);
                            } else {
                                result.setCodeMsg(CodeMsg.ROOM_ID_HAVE_EXISTENCE);
                            }
                            oos.writeObject(result);
                            oos.flush();
                        }
                        //加入房间
                        case "join" -> {
                            // joinId-加入的玩家
                            HashMap<String,String> requestMap = (HashMap<String,String>) ois.readObject();
                            Result result = new Result();
                            HashMap<String, String> resultMap = new HashMap<>();
                            //获取这个房间的对手
                            Room room = roomMapper.selectByRoomId(requestMap.get("joinId"));

                            if (!Objects.isNull(room)) {
                                String rival = room.getCreateUser();
                                resultMap.put("rival",rival);
                                //保存与对手的连接
                                connectMap.put(requestMap.get("fromUser"), oosMap.get(rival));
                                connectMap.put(rival, oosMap.get(requestMap.get("fromUser")));
                                result.setMap(resultMap);
                                result.setCodeMsg(CodeMsg.SUCCESS);
                                oos.writeObject(result);
                                oos.flush();

                                System.out.println(requestMap.get("fromUser"));
                                ObjectOutputStream stream = connectMap.get(requestMap.get("fromUser"));
                                stream.writeUTF("connect");
                                stream.writeObject(requestMap.get("fromUser"));
                                stream.flush();
                            } else {
                                result.setCodeMsg(CodeMsg.ROOM_ID_NOT_EXISTENCE);
                                oos.writeObject(result);
                                oos.flush();
                            }
                        }
                        //下棋
                        case "down" -> {
                            HashMap<String,String> map = (HashMap<String,String>) ois.readObject();

                            ObjectOutputStream stream = connectMap.get(map.get("fromUser"));

                            //发送给对手
                            stream.writeUTF("add");
                            stream.flush();
                            stream.writeObject(map);
                            stream.flush();
                        }
                        //询问
                        case "ask" -> {
                            HashMap<String, String> map = (HashMap<String, String>) ois.readObject();

                            ObjectOutputStream stream = connectMap.get(map.get("fromUser"));
                            stream.writeUTF("decide");
                            stream.flush();
                            stream.writeObject(map.get("request"));
                            stream.flush();
                        }
                        //回到房间
                        case "back" -> {
                            HashMap<String, String> map = (HashMap<String, String>) ois.readObject();

                            ObjectOutputStream stream = connectMap.get(map.get("fromUser"));
                            if (stream != null) {
                                stream.writeUTF("cBack");
                                stream.flush();
                            }

                            //删除连接
                            connectMap.remove(map.get("toUser"));
                            connectMap.remove(map.get("fromUser"));
                            roomMapper.deleteByRoomId(map.get("roomId"));

                            oos.writeUTF("comeback");
                            oos.flush();

                        }
                        //投降
                        case "surrender" -> {
                            HashMap<String, String> map = (HashMap<String, String>) ois.readObject();
                            ObjectOutputStream stream = connectMap.get(map.get("fromUser"));

                            stream.writeUTF("win");
                            stream.flush();
                            stream.writeObject(map.get("fromUser"));
                            stream.flush();
                        }
                        case "result" -> {
                            String data = (String) ois.readObject();
                            String[] split = data.split(",");

                            ObjectOutputStream stream = connectMap.get(split[1]);
                            stream.writeUTF("answer");
                            stream.flush();
                            stream.writeObject(split[0]);
                            stream.flush();

                        }
                        //对话
                        case "say" -> {
                            HashMap<String, String> map = (HashMap<String, String>) ois.readObject();

                            ObjectOutputStream stream = connectMap.get(map.get("fromUser"));
                            if (stream != null) {
                                stream.writeUTF("reply");
                                stream.flush();
                                stream.writeObject(map);
                                stream.flush();
                            }
                        }
                        //登出
                        case "exit" -> {
                            HashMap<String,String> map = (HashMap<String,String>) ois.readObject();
                            //删除token信息
                            tokenMapper.deleteByUsername(map.get("fromUser"));
                            oosMap.remove(map.get("fromUser"));
                            userSet.remove(map.get("fromUser"));
                            isOnline.remove(socket.getInetAddress().toString());
                        }
                        //积分榜
                        case "page" -> {
                            ArrayList<String[]> page = userMapper.page();
                            oos.writeObject(page);
                            oos.flush();
                        }
                        //更新积分
                        case "update" -> {
                            HashMap<String,String> requestMap = (HashMap<String, String>) ois.readObject();
                            userMapper.updateWin(requestMap.get("win"));
                            userMapper.updateLost(requestMap.get("lost"));
                        }
                        //服务器是否断线
                        case "live" -> {

                        }
                        //对手是否断线
                        case "rivalIsLive" -> {
                            String fromUser = (String) ois.readObject();
                            ObjectOutputStream stream = connectMap.get(fromUser);

                            try {
                                stream.writeUTF("isStillLive");
                                stream.flush();
                                oos.writeUTF("isLive");
                                oos.writeObject("Yes");
                                oos.flush();
                            } catch (Exception e){
                                e.printStackTrace();
                                oos.writeUTF("breakDown");
                                oos.flush();
                            }

                        }
                        case "heartBeatFromClient" -> {
                            System.out.println("收到心跳");
                        }
                        default -> System.out.println("未知请求");
                    }
                } catch (Exception e) {//捕捉用户异常退出(例如直接终止程序) 的异常，将用户连接全部断开
                    if (e instanceof SocketException || e instanceof EOFException) {
                        System.out.println("客户端断开");
                        String userName = isOnline.get(socket.getInetAddress().toString());
                        userSet.remove(userName);
                        isOnline.remove(socket.getInetAddress().toString());
                        roomMapper.deleteByUsername(userName);
                        oos.close();
                        ois.close();
                        break;
                    }
                    e.printStackTrace();
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
